        TITL DAI FIRMWARE 3EA00-3EB25  V1.0  Rev.1
        ORG   :EA00
*
*
*
*  =================
*** UTILITY PACKAGE ***
*  =================
*
**************
* (not used) *
**************
*
L3E158  POP   H
        JMP   :EA09
*
*********************
* RETURN AFTER 'GO' *
*********************
*
L3E159  PUSH  H         Returnaddr after 'GO'
        LXI   H,:BADC   Dummy 'saved PC' to prevent
 REM continuation 'G' with start
 REM address
        XTHL            Returnaddr in HL
L3E160  SHLD  :0059     Save HL
        POP   H         in HL: #BADC
 REM Into initialisation
*
**********************
* INITIALISE UTILITY *
**********************
*
* CPU registers are saved in the utility work
* area. Input from the keyboard is awaited.
*
* The address EA42 is the general return address
* for all Utility commands.
*
CALRX   SHLD  :005D     Save PC (next instr)
        PUSH  PSW
        POP   H
        SHLD  :0053     Save PSW
        LXI   H,:0000
        DAD   SP
        SHLD  :005B     Save SP
        XCHG
        SHLD  :0057     Save DE
        MOV   H,B
        MOV   L,C
        SHLD  :0055     Save BC
        CALL  :EDE7     Invert nibbles in CPU
 REM reg save area
        LHLD  :005D     Get addr next instr
        MOV   A,H
        ORA   L
        JZ    :EA3C     If it is 0000 (entry from
 REM BASIC)
 REM Else:
        DCX   H         HL on addr current instr
        MOV   A,M       Get opcode in A
        ANI   :C7
        CPI   :C7
        JNZ   :EA3C     Jump if instr is a RST
        SHLD  :005D     Save addr next instr
L3E162  LXI   H,:EA7D   Startaddr string table
        CALL  :ED2F     Print 'PC UTILITY V3.3'
 REM
* UT command look-up:
 REM
L3E163  CALL  :ED3A     Print car.ret
        MVI   C,:3E
        CALL  :EEB4     Print '>'
        CALL  :ED06     Get keyb input, print char
        LXI   H,:EA42   Returnaddr in HL
        PUSH  H         Save it on stack
        LXI   H,:EA8D   Startaddr table commands
L3E164  INX   H
        CMP   M         Compare input with table
        JC    :EA62     Error if invalid input
        INX   H         )
        MOV   E,M       ) Get pointer to address
        INX   H         ) of part. routine in DE
        MOV   D,M       )
        JNZ   :EA54     Check with next command
        XCHG            Startaddr routine in HL
        PCHL            Go to this routine
*
*********
* ERROR *
*********
*
* The only error message in utility is '?'.
*
* Exit: B preserved, AFCDEHL corrupted.
*
ERROR   CALL  :ED3A     Print car.ret
        MVI   C,:3F
        CALL  :EEB4     Print '?'
ERRST   LHLD  :005B     Get saved SP
        SPHL            Restore stackpointer
        NOP
        NOP
        NOP
        JMP   :EA42     Start again for new input
*
********************
* ENTRY FROM BASIC *
********************
*
RESET   SHLD  :0059     Save HL
        LXI   H,:0000   Addr next instr (dummy)
        JMP   :EA0D     Init utility
*
*************************
* UTILITY SCREEN HEADER *
*************************
*
* 0C is clear screen; 20 is space.
*
MSGSO   DATA  :0C
        DATA  :50       P
        DATA  :43       C
        DATA  :20
        DATA  :55       U
        DATA  :54       T
        DATA  :49       I
        DATA  :4C       L
        DATA  :49       I
        DATA  :54       T
        DATA  :59       Y
        DATA  :20
        DATA  :56       V
        DATA  :33       3
        DATA  :2E       .
        DATA  :33       3
*
        DATA  :00       End table
*
*******************************
* TABLE WITH UTILITY COMMANDS *
*******************************
*
CMDTB   DATA  :42       B
        DBL   :C7A0     return addr to Basic
*
        DATA  :44       D
        DBL   :EAB3     startaddr Display
*
        DATA  :46       F
        DBL   :ED48     startaddr Fill
*
        DATA  :47       G
        DBL   :ED8A     startaddr Go
*
        DATA  :4C       L
        DBL   :EB26     startaddr Look
*
        DATA  :4D       M
        DBL   :EC83     startaddr Move
*
        DATA  :52       R
        DBL   :EF0F     startaddr Read
*
        DATA  :53       S
        DBL   :ED5C     startaddr Substitute
*
        DATA  :56       V
        DBL   :ED77     startaddr Vector Examine
*
        DATA  :57       W
        DBL   :EEE4     startaddr Write
*
        DATA  :58       X
        DBL   :ED6E     startaddr Examine
*
        DATA  :5A       Z
        DBL   :ECBA     startaddr Reset
*
        DATA  :FF       End table
*
***************
* D - DISPLAY *
***************
*
* Displays contents of memory. Two address values
* are required which specify the range of memory
* to be displayed. Break will abort the print out.
*
* Exit: CY=1, All registers corrupted.
*
DISPK   MVI   C,:02     Nr of addr inputs required
        CALL  :EADE     Get laddr and haddr on stack
        DCR   C
        JP    :EA62     Error if only 1 addr given
        POP   D         Haddr in DE
        POP   H         Laddr in HL
 REM
* Direct call entry:
 REM
*DISL1
DISP    CALL  :ED3A     Print car.ret
        CALL  :ED18     Print laddr in ASCII
DISL2   CALL  :ED01     Print space
        MOV   A,M       Get contents laddr
        CALL  :ED1D     Print it in ASCII
        CALL  :ED80     INX H; check if ready
        RC              Quit if ready
        CALL  :EEC2     Scan for Break pressed,
 REM abort if pressed.
        MOV   A,L
        ANI   :0F       Last instr on line?
        JZ    :EABE     Then car.ret and continue
        JMP   :EAC4     Next addr
*
**************************
* ADDRESS ARGUMENT INPUT *
**************************
*
* The keyboard is scanned and the inputs are
* evaluated.
* (C) address arguments will be input and put on
* stack (LIFO). On return, C contains the
* difference between number entered and number
* desired. At least one argument is returned.
* Only the last 4 hex characters are used for the
* address value. Arguments are delimited by a
* space. The entry is terminated by CR, ESC, last
* argument or an invalid character (then error
* exit). Escape returns with CY set.
*
* Entry: C: max. nr of datablocks/addresses.
* Exit:  B: Last character typed in (terminator).
*        AFHL corrupted, DE preserved.
*
ADALT   XRA   A         A=0
        CMP   C         Max nr of inputs reached?
        RZ              Then return
ADARG   LXI   H,:0000
ADACL   CALL  :ED06     Scan keyb, print char
        MOV   B,A       Store char in B
        CALL  :EB15     Convert it to hex
        JC    :EAF4     If char not 0-F: check if
 REM delimiter
ADACE   DAD   H         )
        DAD   H         ) Move bits 1 nibble
        DAD   H         ) (compose addr from inputs)
        DAD   H         )
        ADD   L         Add hex char to L
        MOV   L,A       and store it
        JMP   :EAE1     Next char
 REM
* Check for delimiter/terminator:
 REM
ADADC   XTHL            Save given addr on stack
        PUSH  H         Save returnaddr again
        DCR   C         decr input counter
        MOV   A,B       Get char last input
        CPI   :20       Space ?
        JZ    :EADB     Then get next addr
        CPI   :0D       Car.ret ?
        RZ              Then ready
        CPI   :12       Escape?
        STC             Then CY=1
        RZ              and return
        JMP   :EA62     Else goto Error
 REM
* As ADARG, but carry return if 1st character is
* not a legal hex digit:
 REM
ADART   LXI   H,:0000   Immediate delimiter
        CALL  :ED06     Scan keyb, print char
        MOV   B,A       Store char in B
        CALL  :EB15     Convert it to hex
        RC              Return if no hex char
        JMP   :EAEB     Into previous routine
*
* CONVERT NUMBER FROM ASCII TO HEX-VALUE:
*
* Entry: Character in A (bit 7 must be 0).
* Exit:  CY=0: Hex-value in A.
*        CY=1: Input was not 0-F; (A) useless.
*        BCDEHL preserved.
*
ASHEX   SUI   :30
        RC              Error if #00-#2F
        CPI   :0A
        JC    :EB24     O.K. if number 0-9
        SUI   :07
        CPI   :0A
        RC              Error if #3A-#3F
        CPI   :10
ASHCC   CMC             O.K. if 0-9, A-F
        RET
*
*
*
        UNL
DISL1   EQU DISP
        LST
        END
